#include "fbo.h"

static PFNGLISRENDERBUFFEREXTPROC    glIsRenderbufferEXT    = NULL;
static PFNGLBINDRENDERBUFFEREXTPROC    glBindRenderbufferEXT     = NULL;
static PFNGLDELETERENDERBUFFERSEXTPROC    glDeleteRenderbuffersEXT    = NULL;
static PFNGLGENRENDERBUFFERSEXTPROC    glGenRenderbuffersEXT    = NULL;
static PFNGLRENDERBUFFERSTORAGEEXTPROC    glRenderbufferStorageEXT    = NULL;
static PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC    glGetRenderbufferParameterivEXT    = NULL;
static PFNGLISFRAMEBUFFEREXTPROC    glIsFramebufferEXT    = NULL;
static PFNGLBINDFRAMEBUFFEREXTPROC   glBindFramebufferEXT    = NULL;
static PFNGLDELETEFRAMEBUFFERSEXTPROC    glDeleteFramebuffersEXT    = NULL;
static PFNGLGENFRAMEBUFFERSEXTPROC    glGenFramebuffersEXT    = NULL;
static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC    glCheckFramebufferStatusEXT    = NULL;
static PFNGLFRAMEBUFFERTEXTURE1DEXTPROC    glFramebufferTexture1DEXT    = NULL;
static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC    glFramebufferTexture2DEXT    = NULL;
static PFNGLFRAMEBUFFERTEXTURE3DEXTPROC    glFramebufferTexture3DEXT    = NULL;
static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC    glFramebufferRenderbufferEXT    = NULL;
static PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC    glGetFramebufferAttachmentParameterivEXT    = NULL;

static int extensions_loaded=0;

static int load_framebuffer_extensions()
{
	if (extensions_loaded) return 1;
	
	if (!(glIsRenderbufferEXT=load_extension("glIsRenderbufferEXT"))) return 0;
	if (!(glBindRenderbufferEXT=load_extension("glBindRenderbufferEXT"))) return 0;
	if (!(glDeleteRenderbuffersEXT=load_extension("glDeleteRenderbuffersEXT"))) return 0;
	if (!(glGenRenderbuffersEXT=load_extension("glGenRenderbuffersEXT"))) return 0;
	if (!(glRenderbufferStorageEXT=load_extension("glRenderbufferStorageEXT"))) return 0;
	if (!(glGetRenderbufferParameterivEXT=load_extension("glGetRenderbufferParameterivEXT"))) return 0;
	if (!(glIsFramebufferEXT=load_extension("glIsFramebufferEXT"))) return 0;
	if (!(glBindFramebufferEXT=load_extension("glBindFramebufferEXT"))) return 0;
	if (!(glDeleteFramebuffersEXT=load_extension("glDeleteFramebuffersEXT"))) return 0;
	if (!(glGenFramebuffersEXT=load_extension("glGenFramebuffersEXT"))) return 0;
	if (!(glCheckFramebufferStatusEXT=load_extension("glCheckFramebufferStatusEXT"))) return 0;
	if (!(glFramebufferTexture1DEXT=load_extension("glFramebufferTexture1DEXT"))) return 0;
	if (!(glFramebufferTexture2DEXT=load_extension("glFramebufferTexture2DEXT"))) return 0;
	if (!(glFramebufferTexture3DEXT=load_extension("glFramebufferTexture3DEXT"))) return 0;
	if (!(glFramebufferRenderbufferEXT=load_extension("glFramebufferRenderbufferEXT"))) return 0;
	if (!(glGetFramebufferAttachmentParameterivEXT=load_extension("glGetFramebufferAttachmentParameterivEXT"))) return 0;
	
	printf("all framebuffer extensions loaded successfully!\n");
	
	extensions_loaded=1;
	return 1;
}

rat_fbo *rat_fbo_create(unsigned int sizex,unsigned int sizey,int format)
{
	rat_fbo *fbo;
	int fb,rb,tex;

	if (!extensions_loaded)
	{
		if (!load_framebuffer_extensions())
		{
			printf("failed to load framebuffer extensions!\n");
			return NULL;
		}
	}
	
	fbo=(rat_fbo *)malloc(sizeof(rat_fbo));
	
	glGenFramebuffersEXT(1,&fb);
	glGenTextures(1,&tex);
	glGenRenderbuffersEXT(1,&rb);
	
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fb);

	glBindTexture(GL_TEXTURE_2D,tex);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
    
    glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA16F_ARB,sizex,sizey,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
    glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,GL_COLOR_ATTACHMENT0_EXT,GL_TEXTURE_2D,tex,0);
    
    glBindRenderbufferEXT(GL_RENDERBUFFER_EXT,rb);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT,GL_DEPTH_COMPONENT24,sizex,sizey);
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,GL_DEPTH_ATTACHMENT_EXT,GL_RENDERBUFFER_EXT,rb);
	
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
	
	fbo->framebuffer=fb;
	fbo->renderbuffer=rb;
	fbo->texture=tex;
	fbo->format=format;
	
	return fbo;
}

void rat_fbo_destroy(rat_fbo *fbo)
{
	glDeleteRenderbuffersEXT(1,&fbo->renderbuffer);
	glDeleteFramebuffersEXT(1,&fbo->framebuffer);
	glDeleteTextures(1,&fbo->texture);
	free(fbo);
}

void rat_fbo_bind(rat_fbo *fbo)
{
	glBindTexture(GL_TEXTURE_2D,0);
	if (!fbo)
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0);
	else
		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,fbo->framebuffer);
}

